package com.satan.juc.demo23;

import org.junit.Test;

import java.util.Random;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @Author: Demon
 * @Date: 2024/3/31 00:42
 * @Description:
 **/
public class CompletableFutureExample {
    @Test
    public void test1() throws ExecutionException, InterruptedException {
        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
            System.out.println("supplyAsync");
            return "supplyAsync的返回值";
        });
        System.out.println(future.get());
    }

    @Test
    public void test2() throws ExecutionException, InterruptedException {
        CompletableFuture.runAsync(() -> {
            System.out.println(Thread.currentThread().getName() + " 执行异步任务 runAsync");
        });

        String result = CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread().getName() + " 执行异步任务 supplyAsync");
            return "supplyAsync的返回值";
        }).get();

        System.out.println(result);
    }

    @Test
    public void test3() throws ExecutionException, InterruptedException {
        ExecutorService executor = Executors.newFixedThreadPool(2);
        CompletableFuture.runAsync(() -> {
            System.out.println(Thread.currentThread().getName() + " 执行异步任务 runAsync");
        }, executor);

        String result = CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread().getName() + " 执行异步任务 supplyAsync");
            return "supplyAsync的返回值";
        }, executor).get();

        System.out.println(result);
    }

    //在本线程中等待
    @Test
    public void test4() throws ExecutionException, InterruptedException {
        CompletableFuture<String> completableFuture = new CompletableFuture<String>();
        new Thread(() -> {
            try {
                Thread.sleep(1000);
                System.out.println("子线程执行");
                completableFuture.complete("success");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
        try {
            //主线程阻塞，等待完成
            String result = completableFuture.get();
            System.out.println("主线程获得结果: " + result);
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        }
    }

    //thenRun在本线程中等待
    @Test
    public void test5() throws ExecutionException, InterruptedException {
        CompletableFuture
                .runAsync(() -> System.out.println(Thread.currentThread().getName() + " runAsync 执行"))
                .thenRun(() -> System.out.println(Thread.currentThread().getName() + " thenRun 执行"));
    }

    //thenRunAsync在异步线程中等待
    @Test
    public void test6() throws ExecutionException, InterruptedException {
        CompletableFuture
                .runAsync(() -> System.out.println(Thread.currentThread().getName() + " runAsync 执行"))
                .thenRunAsync(() -> System.out.println(Thread.currentThread().getName() + " thenRunAsync 执行"));
    }

    //thenAccept接受参数，但不返回结果，只进不出。
    @Test
    public void test7() throws ExecutionException, InterruptedException {
        CompletableFuture
                .supplyAsync(() -> {
                    System.out.println(Thread.currentThread().getName() + " runAsync 执行");
                    return "supplyAsync返回值";
                })
                .thenAccept(i -> System.out.println(Thread.currentThread().getName() + " thenRunAsync 执行。上一步结果：" + i));
    }

    //thenApply接收参数，也输出结果。
    @Test
    public void test8() throws ExecutionException, InterruptedException {
        CompletableFuture<String> completableFuture = CompletableFuture
                .supplyAsync(() -> {
                    System.out.println(Thread.currentThread().getName() + " runAsync 执行");
                    return "supplyAsync返回值";
                })
                .thenApply(i -> {
                    System.out.println(Thread.currentThread().getName() + " thenRunAsync 执行。上一步结果：" + i);
                    return "thenApply返回值";
                });
        System.out.println(completableFuture.get());
    }

    //thenCompose将多个CompletableFuture组合。
    @Test
    public void test9() throws ExecutionException, InterruptedException {
        CompletableFuture<String> future = CompletableFuture
                .supplyAsync(() -> {
                    System.out.println(Thread.currentThread().getName() + " supplyAsync（第1个） 执行");
                    return "supplyAsync（第1个）返回值";
                })
                .thenCompose(value ->
                        CompletableFuture.supplyAsync(() -> {
                            System.out.println(Thread.currentThread().getName() + " supplyAsync（第2个） 执行");
                            return value + "; supplyAsync（第2个）返回值";
                        })
                );
        System.out.println(future.get());
    }

    //thenCombine（合并两个/有返回值）
    @Test
    public void test10() throws ExecutionException, InterruptedException {
        CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread().getName() + " supplyAsync（第1个） 执行");
            return 1;
        });
        CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread().getName() + " supplyAsync（第2个） 执行");
            return 2;
        });
        CompletableFuture<Integer> result = future1.thenCombine(future2, (number1, number2) -> {
            return number1 + number2;
        });
        System.out.println(result.get());
    }

    //allOf会等待所有的任务执行完毕。
    //注意，allOf返回值为CompletableFuture<Void>型，所以无法获得返回值。
    @Test
    public void test11() throws ExecutionException, InterruptedException {
        Random rand = new Random();
        CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(rand.nextInt(1000));
                System.out.println(Thread.currentThread().getName() + " supplyAsync（第1个） 睡眠结束");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return 100;
        });
        CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(rand.nextInt(1000));
                System.out.println(Thread.currentThread().getName() + " supplyAsync（第2个） 睡眠结束");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "abc";
        });
        CompletableFuture<Void> f = CompletableFuture.allOf(future1, future2);
        f.get();//会阻塞在这里，等待所有的任务执行完毕
        System.out.println("所有任务执行完毕");
    }

    //anyOf等待任一任务执行完毕。
    @Test
    public void test12() throws ExecutionException, InterruptedException {
        Random rand = new Random();
        CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(rand.nextInt(1000));
                System.out.println(Thread.currentThread().getName() + " supplyAsync（第1个） 睡眠结束");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return 100;
        });
        CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(rand.nextInt(1000));
                System.out.println(Thread.currentThread().getName() + " supplyAsync（第2个） 睡眠结束");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "abc";
        });
        CompletableFuture<Object> f = CompletableFuture.anyOf(future1, future2);
        System.out.println(f.get());
    }

    //thenAcceptBoth（合并两个/无返回值）


    @Test
    public void test13() throws ExecutionException, InterruptedException {
        CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread().getName() + " supplyAsync（第1个） 睡眠结束");
            return "abc";
        });
        CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread().getName() + " supplyAsync（第2个） 睡眠结束");
            return "def";
        });
        future1.thenAcceptBoth(future2, (x, y) -> System.out.println(x + y)).get();
    }
    //acceptEither（合并两个/无返回值）
    //注意：所有的CompletableFuture的返回值必须是一样的。
    //比如下边，如果future1为CompletableFuture<Integer>，future2为CompletableFuture<String>则会直接报错。
    @Test
    public void test14() throws ExecutionException, InterruptedException {
        Random rand = new Random();
        CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(rand.nextInt(1000));
                System.out.println(Thread.currentThread().getName() + " supplyAsync（第1个） 睡眠结束");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "abc";
        });
        CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(rand.nextInt(1000));
                System.out.println(Thread.currentThread().getName() + " supplyAsync（第2个） 睡眠结束");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "def";
        });
        future1.acceptEither(future2, x -> System.out.println(x)).get();
    }

    //applyToEither（合并两个/有返回值）
    @Test
    public void test15() throws ExecutionException, InterruptedException {
        CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread().getName() + " supplyAsync（第1个） 执行");
            return "abc";
        });
        CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread().getName() + " supplyAsync（第2个） 执行");
            return "def";
        });
        String result = future1.applyToEither(future2, x -> {
            System.out.println(Thread.currentThread().getName() + " applyToEither 执行");
            return "此返回值所在的线程执行的快：" + x;
        }).get();
        System.out.println(Thread.currentThread().getName() + " 结果：" + result);
    }
    //whenComplete（无返回值）异步子线程执行完之后，会在外部线程中执行接下来的操作。
    @Test
    public void test16() throws ExecutionException, InterruptedException {
        CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread().getName() + " supplyAsync 执行");
//            int i = 1 / 0;
            return "abc";
        }).whenComplete((s, throwable) -> {
            System.out.println(Thread.currentThread().getName() + " whenComplete 执行");
            System.out.println("上一步的结果：" + s);
            System.out.println("上一步的异常：" + throwable.getMessage());
        });
    }
    //whenCompleteAsync异步子线程执行完之后，在这个异步子线程中执行接下来的操作。
    @Test
    public void test17() throws ExecutionException, InterruptedException {
        CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread().getName() + " supplyAsync 执行");
            return "abc";
        }).whenCompleteAsync((s, throwable) -> {
            System.out.println(Thread.currentThread().getName() + " whenCompleteAsync 执行");
            System.out.println("上一步的结果：" + s);
            System.out.println("上一步的异常：" + throwable.getMessage());
        });
    }
    //handle接受2个参数，第一个参数为上一次任务的返回结果，第二个参数表示异常对象，
    //handle需要有返回结果，所以这个方法的使用场景可以是：尽管之前的执行的任务异常，仍然需要有默认返回值。
    @Test
    public void test18() throws ExecutionException, InterruptedException {
        String result = CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread().getName() + " supplyAsync 执行");
            int i = 1 / 0;
            return "abc";
        }).handle((s, throwable) -> {
            System.out.println(Thread.currentThread().getName() + " whenComplete 执行");
            System.out.println("上一步的结果：" + s);
            if (throwable != null) {
                System.out.println("上一步的异常：" + throwable.getMessage());
                return "产生异常了。";
            }
            return "上一步的返回值：" + s;
        }).get();
        System.out.println(result);
    }
    //exceptionally此方法和handle类似，不过它只接受一个参数即异常对象，且也是需要返回一个结果。
    @Test
    public void test19() throws ExecutionException, InterruptedException {
        String result = CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread().getName() + " supplyAsync 执行");
            int i = 1 / 0;
            return "abc";
        }).exceptionally(throwable -> {
            System.out.println(Thread.currentThread().getName() + " exceptionally 执行");
            return "产生异常了";
        }).get();
        System.out.println(result);
    }
    //get()线程阻塞
    @Test
    public void test20() throws ExecutionException, InterruptedException {
        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread().getName() + " supplyAsync 执行");
            return "abc";
        });
        String s = future.get();
        System.out.println(s);
    }
}
